home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / Level 0 Macintosh 29Sep94 / Files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  24.7 KB  |  820 lines  |  [TEXT/KAHL]

  1. /* Files.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #ifdef THINK_C
  25.     #pragma options(pack_enums)
  26. #endif
  27. #include <Files.h>
  28. #include <Folders.h>
  29. #include <Finder.h>
  30. #include <Script.h>
  31. #include <Events.h>
  32. #include <Errors.h>
  33. #include <StandardFile.h>
  34. #ifdef THINK_C
  35.     #pragma options(!pack_enums)
  36. #endif
  37.  
  38. #include "Files.h"
  39. #include "Memory.h"
  40. #include "Array.h"
  41.  
  42.  
  43. /* open file abstraction.  for efficiency, we ought to be having buffers */
  44. /* and all kinds of stuff in here, but we're too lazy to implement it. */
  45. struct FileType
  46.     {
  47.         /* refnum for Macintosh file system OS calls */
  48.         short                                    Refnum;
  49.     };
  50.  
  51.  
  52. /* global variable containing the last I/O error.  Haven't decided what */
  53. /* to use it for yet. */
  54. static OSErr                            LastError;
  55.  
  56. /* things for debugging */
  57. EXECUTE(static ArrayRec*    FileSpecList;)
  58. EXECUTE(static ArrayRec*    FileDescriptorList;)
  59.  
  60.  
  61. /* initialize the file subsystem.  should only be called from Screen */
  62. MyBoolean                        Eep_InitializeFiles(void)
  63.     {
  64.         APRINT(("+Eep_InitializeFiles"));
  65. #if DEBUG
  66.         FileSpecList = NewArray();
  67.         if (FileSpecList == NIL)
  68.             {
  69.              FailurePoint1:
  70.                 APRINT(("-Eep_InitializeFiles failed"));
  71.                 return False;
  72.             }
  73.         FileDescriptorList = NewArray();
  74.         if (FileDescriptorList == NIL)
  75.             {
  76.              FailurePoint2:
  77.                 DisposeArray(FileSpecList);
  78.                 goto FailurePoint1;
  79.             }
  80. #endif
  81.         APRINT(("-Eep_InitializeFiles"));
  82.         return True;
  83.     }
  84.  
  85.  
  86. /* shutdown the file subsystem. */
  87. void                                Eep_ShutdownFiles(void)
  88.     {
  89.         APRINT(("+Eep_ShutdownFiles"));
  90. #if DEBUG
  91.         ERROR(ArrayGetLength(FileSpecList) != 0,PRERR(AllowResume,
  92.             "Eep_ShutdownFiles:  some file specs still exist"));
  93.         ERROR(ArrayGetLength(FileDescriptorList) != 0,PRERR(AllowResume,
  94.             "FileDescriptorList:  some files are still open"));
  95.         DisposeArray(FileSpecList);
  96.         DisposeArray(FileDescriptorList);
  97. #endif
  98.         APRINT(("-Eep_ShutdownFiles"));
  99.     }
  100.  
  101.  
  102. /* this is an internal routine -- do not use */
  103. #if DEBUG
  104. MyBoolean                        Eep_RegisterFileSpec(FileSpec* Spec)
  105.     {
  106.         CheckPtrExistence(Spec);
  107.         return ArrayAppendElement(FileSpecList,Spec);
  108.     }
  109. #endif
  110.  
  111.  
  112. /* this routine validates a file specification to make sure it exists */
  113. #if DEBUG
  114. void                            ValidateFileSpec(FileSpec* Spec)
  115.     {
  116.         CheckPtrExistence(Spec);
  117.         ERROR(-1 == ArrayFindElement(FileSpecList,Spec),PRERR(ForceAbort,
  118.             "ValidateFileSpec:  undefined file specification"));
  119.     }
  120. #endif
  121.  
  122.  
  123. /* make a copy of a file specification */
  124. /* this routine does not perform operations on file descriptors. */
  125. FileSpec*                        DuplicateFileSpec(FileSpec* Original)
  126.     {
  127.         FileSpec*                    Copy;
  128.  
  129.         APRINT(("+DuplicateFileSpec %xl",Original));
  130.         ERROR(-1 == ArrayFindElement(FileSpecList,Original),PRERR(ForceAbort,
  131.             "DuplicateFileSpec:  undefined file specification"));
  132.         Copy = (FileSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  133.         if (Copy != NIL)
  134.             {
  135.                 CopyData((char*)Original,(char*)Copy,sizeof(FSSpec));
  136.                 if (!Eep_RegisterFileSpec(Copy))
  137.                     {
  138.                         ReleasePtr((char*)Copy);
  139.                         Copy = NIL;
  140.                     }
  141.             }
  142.         APRINT(("-DuplicateFileSpec %xl",Copy));
  143.         return Copy;
  144.     }
  145.  
  146.  
  147. /* dispose of a file specification thing */
  148. void                                DisposeFileSpec(FileSpec* Spec)
  149.     {
  150.         APRINT(("+DisposeFileSpec %xl",Spec));
  151.         ERROR(-1 == ArrayFindElement(FileSpecList,Spec),PRERR(ForceAbort,
  152.             "DisposeFileSpec:  undefined file specification"));
  153.         EXECUTE(ArrayDeleteElement(FileSpecList,ArrayFindElement(FileSpecList,Spec)));
  154.         ReleasePtr((char*)Spec);
  155.         APRINT(("-DisposeFileSpec"));
  156.     }
  157.  
  158.  
  159. /* create a new temporary file with a known unique name, and return a specification */
  160. /* leading to it.  the creator and filetype codes may or may not be used by */
  161. /* the implementation; the Macintosh does use them.  The file is actually created. */
  162. /* this routine does not perform operations on file descriptors. */
  163. FileSpec*                        NewTempFileSpec(unsigned long Creator, unsigned long FileType)
  164.     {
  165.         short                            vRefNum;
  166.         long                            DirID;
  167.         FSSpec*                        Temp;
  168.         unsigned char            Name[32] = "\pTempFile........";
  169.         int                                Scan;
  170.         unsigned long            Key;
  171.  
  172.         APRINT(("+NewTempFileSpec"));
  173.         FindFolder(kOnSystemDisk,kTemporaryFolderType,kCreateFolder,&vRefNum,&DirID);
  174.         Temp = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  175.         if (Temp == NIL)
  176.             {
  177.                 APRINT(("-NewTempFileSpec NIL"));
  178.                 return NIL;
  179.             }
  180.         Key = TickCount();
  181.      TryPoint:
  182.         for (Scan = 0; Scan < 8; Scan += 1)
  183.             {
  184.                 Name[Scan + 9] = ((Key >> (Scan * 4)) & 0x0f) + 'a';
  185.             }
  186.         FSMakeFSSpec(vRefNum,DirID,Name,Temp);
  187.         LastError = FSpCreate(Temp,Creator,FileType,smSystemScript);
  188.         if (LastError == dupFNErr)
  189.             {
  190.                 Key += 1;
  191.                 goto TryPoint;
  192.             }
  193.         if (LastError != noErr)
  194.             {
  195.                 ReleasePtr((char*)Temp);
  196.                 Temp = NIL;
  197.             }
  198.         if (Temp != NIL)
  199.             {
  200.                 if (!Eep_RegisterFileSpec((FileSpec*)Temp))
  201.                     {
  202.                         ReleasePtr((char*)Temp);
  203.                         Temp = NIL;
  204.                     }
  205.             }
  206.         APRINT(("-NewTempFileSpec %r",Temp));
  207.         return (FileSpec*)Temp;
  208.     }
  209.  
  210.  
  211. /* create a file spec leading to a named preference file.  The location of preference */
  212. /* files are implementation defined:  UNIX may put them in the user's home directory */
  213. /* with a leading period; Macintosh puts them in a "Preferences" folder.  The file */
  214. /* is actually created unless it already exists.  PrefsFileName is a null terminated */
  215. /* string. */
  216. /* this routine does not perform operations on file descriptors. */
  217. FileSpec*                        NewPrefsFileSpec(char* PrefsFileName, unsigned long Creator,
  218.                                             unsigned long FileType)
  219.     {
  220.         short                            vRefNum;
  221.         long                            DirID;
  222.         FSSpec*                        Temp;
  223.         unsigned char            Name[32];
  224.         int                                Scan;
  225.  
  226.         APRINT(("+NewPrefsFileSpec name = %t",PrefsFileName));
  227.         FindFolder(kOnSystemDisk,kPreferencesFolderType,kCreateFolder,&vRefNum,&DirID);
  228.         Temp = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  229.         if (Temp == NIL)
  230.             {
  231.                 APRINT(("-NewPrefsFileSpec NIL"));
  232.                 return NIL;
  233.             }
  234.         Scan = 0;
  235.         while ((Scan < 31) && (PrefsFileName[Scan] != 0))
  236.             {
  237.                 Name[Scan + 1] = PrefsFileName[Scan];
  238.                 Scan += 1;
  239.             }
  240.         Name[0] = Scan;
  241.         FSMakeFSSpec(vRefNum,DirID,Name,Temp);
  242.         LastError = FSpCreate(Temp,Creator,FileType,smSystemScript);
  243.         if (!Eep_RegisterFileSpec((FileSpec*)Temp))
  244.             {
  245.                 ReleasePtr((char*)Temp);
  246.                 Temp = NIL;
  247.             }
  248.         APRINT(("-NewPrefsFileSpec %r",Temp));
  249.         return (FileSpec*)Temp;
  250.     }
  251.  
  252.  
  253. /* present a dialog box allowing the user to select where to create a new file. */
  254. /* If the file will overwrite an existing file, verify this with the user and then */
  255. /* delete the existing file before returning. DefaultFileName is a null terminated */
  256. /* string. */
  257. /* this routine does not perform operations on file descriptors. */
  258. FileSpec*                        PutFile(char* DefaultFileName)
  259.     {
  260.         unsigned char            Name[32];
  261.         StandardFileReply    MySFR;
  262.         int                                Scan;
  263.         FSSpec*                        ReturnValue;
  264.  
  265.         APRINT(("+PutFile name = %t",DefaultFileName));
  266.         LastError = noErr;
  267.         Scan = 0;
  268.         while ((Scan < 31) && (DefaultFileName[Scan] != 0))
  269.             {
  270.                 Name[Scan + 1] = DefaultFileName[Scan];
  271.                 Scan += 1;
  272.             }
  273.         Name[0] = Scan;
  274.         StandardPutFile(NIL,Name,&MySFR);
  275.         if (MySFR.sfGood)
  276.             {
  277.                 if (MySFR.sfReplacing)
  278.                     {
  279.                         FSpDelete(&MySFR.sfFile);
  280.                     }
  281.                 ReturnValue = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  282.                 if (ReturnValue == NIL)
  283.                     {
  284.                         APRINT(("-PutFile NIL"));
  285.                         return NIL;
  286.                     }
  287.                 *ReturnValue = MySFR.sfFile;
  288.                 if (MySFR.sfReplacing)
  289.                     {
  290.                         FSpDelete(&MySFR.sfFile);
  291.                     }
  292.             }
  293.          else
  294.             {
  295.                 ReturnValue = NIL;
  296.             }
  297.         if (ReturnValue != NIL)
  298.             {
  299.                 if (!Eep_RegisterFileSpec((FileSpec*)ReturnValue))
  300.                     {
  301.                         ReleasePtr((char*)ReturnValue);
  302.                         ReturnValue = NIL;
  303.                     }
  304.             }
  305.         APRINT(("-PutFile %r",ReturnValue));
  306.         return (FileSpec*)ReturnValue;
  307.     }
  308.  
  309.  
  310. /* let the user find a file with the specified list of types.  Whether the types */
  311. /* are actually used is implementation defined.  The Macintosh uses up to 4 types. */
  312. /* returns NIL if the operation was cancelled. */
  313. /* this routine does not perform operations on file descriptors. */
  314. FileSpec*                        GetFileStandard(long NumFileTypes, unsigned long* ArrayOfFileTypes)
  315.     {
  316.         StandardFileReply    MySFR;
  317.         FSSpec*                        Where;
  318.  
  319.         APRINT(("+GetFileStandard"));
  320.         ERROR((NumFileTypes != 0) && (ArrayOfFileTypes == NIL),PRERR(ForceAbort,
  321.             "GetFileStandard:  file type array is NIL"));
  322.         LastError = noErr;
  323.         StandardGetFile(NIL,NumFileTypes,ArrayOfFileTypes,&MySFR);
  324.         if (MySFR.sfGood)
  325.             {
  326.  
  327.                 Where = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  328.                 if (Where != NIL)
  329.                     {
  330.                         *Where = MySFR.sfFile;
  331.                     }
  332.             }
  333.          else
  334.             {
  335.                 Where = NIL;
  336.             }
  337.         if (Where != NIL)
  338.             {
  339.                 if (!Eep_RegisterFileSpec((FileSpec*)Where))
  340.                     {
  341.                         ReleasePtr((char*)Where);
  342.                         Where = NIL;
  343.                     }
  344.             }
  345.         APRINT(("-GetFileStandard %r",Where));
  346.         return (FileSpec*)Where;
  347.     }
  348.  
  349.  
  350. /* get any file.  like GetFileStandard except it shows all possible files */
  351. /* this routine does not perform operations on file descriptors. */
  352. FileSpec*                        GetFileAny(void)
  353.     {
  354.         StandardFileReply    MySFR;
  355.         FSSpec*                        Where;
  356.  
  357.         APRINT(("+GetFileAny"));
  358.         LastError = noErr;
  359.         StandardGetFile(NIL,-1,NIL,&MySFR);
  360.         if (MySFR.sfGood)
  361.             {
  362.                 Where = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  363.                 if (Where != NIL)
  364.                     {
  365.                         *Where = MySFR.sfFile;
  366.                     }
  367.             }
  368.          else
  369.             {
  370.                 Where = NIL;
  371.             }
  372.         if (Where != NIL)
  373.             {
  374.                 if (!Eep_RegisterFileSpec((FileSpec*)Where))
  375.                     {
  376.                         ReleasePtr((char*)Where);
  377.                         Where = NIL;
  378.                     }
  379.             }
  380.         APRINT(("-GetFileAny %r",Where));
  381.         return (FileSpec*)Where;
  382.     }
  383.  
  384.  
  385. /* return a pointer containing a non-null-terminated string which is the filename. */
  386. /* this routine does not perform operations on file descriptors. */
  387. char*                                ExtractFileName(FileSpec* Spec)
  388.     {
  389.         char*                            Name;
  390.  
  391.         CheckPtrExistence(Spec);
  392.         ERROR(-1 == ArrayFindElement(FileSpecList,Spec),PRERR(ForceAbort,
  393.             "ExtractFileName:  undefined file specification"));
  394.         Name = AllocPtrCanFail(((FSSpec*)Spec)->name[0],"ExtractFileName");
  395.         if (Name != NIL)
  396.             {
  397.                 CopyData((char*)&(((FSSpec*)Spec)->name[1]),&(Name[0]),((FSSpec*)Spec)->name[0]);
  398.             }
  399.         return Name;
  400.     }
  401.  
  402.  
  403. /* create a file.  Returns True if the creation succeeded.  Whether or not */
  404. /* the Creator and FileType codes are used is implementation defined.  The Macintosh */
  405. /* does use them. */
  406. /* this routine does not perform operations on file descriptors. */
  407. MyBoolean                        CreateFile(FileSpec* FileLocation, unsigned long Creator,
  408.                                             unsigned long FileType)
  409.     {
  410.         APRINT(("+CreateFile name=%p dir=%l vol=%s",(*(FSSpec*)FileLocation).name,
  411.             (*(FSSpec*)FileLocation).parID,(*(FSSpec*)FileLocation).vRefNum));
  412.         CheckPtrExistence(FileLocation);
  413.         ERROR(-1 == ArrayFindElement(FileSpecList,FileLocation),PRERR(ForceAbort,
  414.             "CreateFile:  undefined file specification"));
  415.         LastError = FSpCreate((FSSpec*)FileLocation,Creator,FileType,smSystemScript);
  416.         APRINT(("-CreateFile err=%s",LastError));
  417.         return (LastError == noErr);
  418.     }
  419.  
  420.  
  421. /* delete a file.  The file must not be in use.  Returns True if successful */
  422. /* this routine does not perform operations on file descriptors. */
  423. MyBoolean                        DeleteFile(FileSpec* FileLocation)
  424.     {
  425.         APRINT(("+DeleteFile"));
  426.         CheckPtrExistence(FileLocation);
  427.         ERROR(-1 == ArrayFindElement(FileSpecList,FileLocation),PRERR(ForceAbort,
  428.             "DeleteFile:  undefined file specification"));
  429.         LastError = FSpDelete((FSSpec*)FileLocation);
  430.         APRINT(("-DeleteFile err=%s",LastError));
  431.         return (LastError == noErr);
  432.     }
  433.  
  434.  
  435. /* Open a file for the specified access.  Returns True if successful. */
  436. /* this routine DOES perform operations on file descriptors. */
  437. MyBoolean                        OpenFile(FileSpec* FileLocation, FileType** FileRefOut,
  438.                                             FileModesType FileAccessMode)
  439.     {
  440.         FileType*                    FileRef;
  441.         int                                Permission;
  442.  
  443.         APRINT(("+OpenFile name=%p dir=%l vol=%s",(*(FSSpec*)FileLocation).name,
  444.             (*(FSSpec*)FileLocation).parID,(*(FSSpec*)FileLocation).vRefNum));
  445.         CheckPtrExistence(FileLocation);
  446.         ERROR(-1 == ArrayFindElement(FileSpecList,FileLocation),PRERR(ForceAbort,
  447.             "OpenFile:  undefined file specification"));
  448.         FileRef = (FileType*)AllocPtrCanFail(sizeof(FileType),"FileType");
  449.         if (FileRef == NIL)
  450.             {
  451.              FailurePoint1:
  452.                 APRINT(("-OpenFile failed"));
  453.                 return False;
  454.             }
  455.         switch (FileAccessMode)
  456.             {
  457.                 default:
  458.                     EXECUTE(PRERR(ForceAbort,"OpenFile:  bad file permission specifier"));
  459.                     break;
  460.                 case eReadOnly:
  461.                     Permission = fsRdPerm;
  462.                     break;
  463.                 case eReadAndWrite:
  464.                     Permission = fsRdWrPerm;
  465.                     break;
  466.             }
  467.         LastError = FSpOpenDF((FSSpec*)FileLocation,Permission,&(FileRef->Refnum));
  468.         if (LastError != noErr)
  469.             {
  470.                 ReleasePtr((char*)FileRef);
  471.                 APRINT((" Error",LastError));
  472.                 goto FailurePoint1;
  473.             }
  474.         EXECUTE(if (!ArrayAppendElement(FileDescriptorList,FileRef))
  475.             {FSClose(FileRef->Refnum); ReleasePtr((char*)FileRef); FileRef = NIL;
  476.             goto FailurePoint1;})
  477.         *FileRefOut = FileRef;
  478.         APRINT(("-OpenFile %r %s",FileRef,FileRef->Refnum));
  479.         return True;
  480.     }
  481.  
  482.  
  483. /* close a file.  The file must have been open.  Implicitly calls FlushLocalBuffers. */
  484. /* this routine DOES perform operations on file descriptors. */
  485. void                                CloseFile(FileType* FileRef)
  486.     {
  487.         APRINT(("+CloseFile %r %s",FileRef,FileRef->Refnum));
  488.         CheckPtrExistence(FileRef);
  489.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  490.             "CloseFile:  undefined file descriptor"));
  491.         FlushLocalBuffers(FileRef);
  492.         LastError = FSClose(FileRef->Refnum);
  493.         EXECUTE(ArrayDeleteElement(FileDescriptorList,
  494.             ArrayFindElement(FileDescriptorList,FileRef)));
  495.         ReleasePtr((char*)FileRef);
  496.         APRINT(("-CloseFile err=%s",LastError));
  497.     }
  498.  
  499.  
  500. /* make sure all data associated with a file gets written out */
  501. /* this routine DOES perform operations on file descriptors. */
  502. void                                FlushLocalBuffers(FileType* FileRef)
  503.     {
  504.         short                            vRefNum;
  505.  
  506.         APRINT(("+FlushLocalBuffers %r %s",FileRef,FileRef->Refnum));
  507.         CheckPtrExistence(FileRef);
  508.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  509.             "FlushLocalBuffers:  undefined file descriptor"));
  510.         LastError = GetVRefNum(FileRef->Refnum,&vRefNum);
  511.         if (LastError == noErr)
  512.             {
  513.                 LastError = FlushVol(NIL,vRefNum);
  514.             }
  515.         APRINT(("-FlushLocalBuffers err=%s",LastError));
  516.     }
  517.  
  518.  
  519. /* write a block of data to the file.  Returns the number of bytes which could */
  520. /* not be written or 0 if all were written. */
  521. /* This is the only function that calls "FSWrite" */
  522. /* this routine DOES perform operations on file descriptors. */
  523. long                                WriteToFile(FileType* FileRef, char* Buffer, long NumBytes)
  524.     {
  525.         APRINT(("+WriteToFile %r %s",FileRef,FileRef->Refnum));
  526.         CheckPtrExistence(FileRef);
  527.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  528.             "WriteToFile:  undefined file descriptor"));
  529.         do
  530.             {
  531.                 long                            NumBytesDone;
  532.  
  533.                 NumBytesDone = NumBytes;
  534.                 LastError = FSWrite(FileRef->Refnum,&NumBytesDone,Buffer);
  535.                 Buffer += NumBytesDone;
  536.                 NumBytes -= NumBytesDone;
  537.                 ERROR(NumBytes != 0,PRERR(AllowResume,
  538.                     "WriteToFile:  couldn't write whole block, trying again"));
  539.             } while ((LastError == noErr) && (NumBytes != 0));
  540.         APRINT(("-WriteToFile err=%s",LastError));
  541.         return NumBytes; /* return number of bytes that couldn't be written */
  542.     }
  543.  
  544.  
  545. /* read a block of data from the file.  Returns the number of bytes which */
  546. /* could not be read, or 0 if all were read. */
  547. /* This is the only function that calls "FSRead" */
  548. /* this routine DOES perform operations on file descriptors. */
  549. long                                ReadFromFile(FileType* FileRef, char* Buffer, long NumBytesDesired)
  550.     {
  551.         EXECUTE(long            TryCount = 0;)
  552.  
  553.         APRINT(("+ReadFromFile %r %s",FileRef,FileRef->Refnum));
  554.         CheckPtrExistence(FileRef);
  555.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  556.             "ReadFromFile:  undefined file descriptor"));
  557.         do
  558.             {
  559.                 long                            NumBytesDone;
  560.  
  561.                 NumBytesDone = NumBytesDesired;
  562.                 LastError = FSRead(FileRef->Refnum,&NumBytesDone,Buffer);
  563.                 Buffer += NumBytesDone;
  564.                 NumBytesDesired -= NumBytesDone;
  565.                 ERROR((NumBytesDesired != 0) && (TryCount > 0),PRERR(AllowResume,
  566.                     "ReadFromFile:  couldn't read whole block, trying again"));
  567.                 EXECUTE(TryCount += 1;)
  568.             } while ((LastError == noErr) && (NumBytesDesired != 0));
  569.         APRINT(("-ReadFromFile err=%s",LastError));
  570.         return NumBytesDesired; /* return number of bytes that couldn't be read */
  571.     }
  572.  
  573.  
  574. /* get the current index into the specified file */
  575. /* this routine DOES perform operations on file descriptors. */
  576. long                                GetFilePosition(FileType* FileRef)
  577.     {
  578.         long                            Where;
  579.  
  580.         APRINT(("+GetFilePosition %r %s",FileRef,FileRef->Refnum));
  581.         CheckPtrExistence(FileRef);
  582.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  583.             "GetFilePosition:  undefined file descriptor"));
  584.         LastError = GetFPos(FileRef->Refnum,&Where);
  585.         APRINT(("-GetFilePosition err=%s",LastError));
  586.         return Where;
  587.     }
  588.  
  589.  
  590. /* move to a new location within the specified file */
  591. /* if the new location is past the EOF, the EOF will be extended to the new location */
  592. /* this routine DOES perform operations on file descriptors. */
  593. MyBoolean                        SetFilePosition(FileType* FileRef, long NewLocation)
  594.     {
  595.         long                            EOF;
  596.  
  597.         APRINT(("+SetFilePosition %r %s",FileRef,FileRef->Refnum));
  598.         CheckPtrExistence(FileRef);
  599.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  600.             "SetFilePosition:  undefined file descriptor"));
  601.         LastError = GetEOF(FileRef->Refnum,&EOF);
  602.         if (EOF < NewLocation)
  603.             {
  604.                 LastError = SetEOF(FileRef->Refnum,NewLocation);
  605.             }
  606.         if (LastError == noErr)
  607.             {
  608.                 LastError = SetFPos(FileRef->Refnum,fsFromStart,NewLocation);
  609.             }
  610.         APRINT(("-SetFilePosition err=%s",LastError));
  611.         return (LastError == noErr);
  612.     }
  613.  
  614.  
  615. /* get the length of the specified file */
  616. /* this routine DOES perform operations on file descriptors. */
  617. long                                GetFileLength(FileType* FileRef)
  618.     {
  619.         long                            EOFPos;
  620.  
  621.         APRINT(("+GetFileLength %r %s",FileRef,FileRef->Refnum));
  622.         CheckPtrExistence(FileRef);
  623.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  624.             "GetFileLength:  undefined file descriptor"));
  625.         LastError = GetEOF(FileRef->Refnum,&EOFPos);
  626.         APRINT(("-GetFileLength err=%s",LastError));
  627.         return EOFPos;
  628.     }
  629.  
  630.  
  631. /* set the length of the specified file. */
  632. /* returns True if everything went well or False if there was an error */
  633. /* If the file could not be extended due to lack of disk space, the EOF */
  634. /* remains unchanged */
  635. /* this routine DOES perform operations on file descriptors. */
  636. MyBoolean                        SetFileLength(FileType* FileRef, long NewFileLength)
  637.     {
  638.         long                            OldEOF;
  639.  
  640.         APRINT(("+SetFileLength %r %s",FileRef,FileRef->Refnum));
  641.         CheckPtrExistence(FileRef);
  642.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  643.             "SetFileLength:  undefined file descriptor"));
  644.         LastError = GetEOF(FileRef->Refnum,&OldEOF);
  645.         if (LastError == noErr)
  646.             {
  647.                 LastError = SetEOF(FileRef->Refnum,NewFileLength);
  648.                 if (LastError == dskFulErr)
  649.                     {
  650.                         SetEOF(FileRef->Refnum,OldEOF);
  651.                     }
  652.             }
  653.         APRINT(("-SetFileLength err=%s",LastError));
  654.         return (LastError == noErr);
  655.     }
  656.  
  657.  
  658. /* copy the entire contents of one file to another.  Data overwrites destination */
  659. /* this routine does not perform operations on file descriptors. */
  660. #define REALBIGBUFFSIZE (65536)
  661. #define LITTLEBUFFSIZE (1024)
  662. MyBoolean                        CopyFile(FileType* Original, FileType* Destination)
  663.     {
  664.         char*                            Buffer;
  665.         MyBoolean                    ReleaseBuffer;
  666.         long                            ActualBufferSize;
  667.         long                            ByteCount;
  668.         char                            EmergencyBuff[LITTLEBUFFSIZE];
  669.  
  670.         CheckPtrExistence(Original);
  671.         CheckPtrExistence(Destination);
  672.         if (!SetFilePosition(Original,0))
  673.             {
  674.                 return False;
  675.             }
  676.         if (!SetFilePosition(Destination,0))
  677.             {
  678.                 return False;
  679.             }
  680.         if (!SetFileLength(Destination,0))
  681.             {
  682.                 return False;
  683.             }
  684.         Buffer = AllocPtrCanFail(REALBIGBUFFSIZE,"CopyFileBuffer");
  685.         if (Buffer != NIL)
  686.             {
  687.                 ActualBufferSize = REALBIGBUFFSIZE;
  688.                 ReleaseBuffer = True;
  689.             }
  690.          else
  691.             {
  692.                 ActualBufferSize = LITTLEBUFFSIZE;
  693.                 ReleaseBuffer = False;
  694.                 Buffer = EmergencyBuff;
  695.             }
  696.         ByteCount = GetFileLength(Original);
  697.         while (ByteCount != 0)
  698.             {
  699.                 long                            LocalBytes;
  700.  
  701.                 if (ByteCount > ActualBufferSize)
  702.                     {
  703.                         LocalBytes = ActualBufferSize;
  704.                     }
  705.                  else
  706.                     {
  707.                         LocalBytes = ByteCount;
  708.                     }
  709.                 if (ReadFromFile(Original,Buffer,LocalBytes) != 0)
  710.                     {
  711.                      FailurePoint:
  712.                         if (ReleaseBuffer)
  713.                             {
  714.                                 ReleasePtr(Buffer);
  715.                             }
  716.                         return False;
  717.                     }
  718.                 if (WriteToFile(Destination,Buffer,LocalBytes) != 0)
  719.                     {
  720.                         goto FailurePoint;
  721.                     }
  722.                 ByteCount -= LocalBytes;
  723.             }
  724.         if (ReleaseBuffer)
  725.             {
  726.                 ReleasePtr(Buffer);
  727.             }
  728.         return True;
  729.     }
  730.  
  731.  
  732. /* create a temporary file in the directory.  the file is actually created so it */
  733. /* exists (so nobody can grab it out from under you). */
  734. /* this routine DOES perform operations on file descriptors. */
  735. FileSpec*                        NewTempFileInTheSameDirectory(FileSpec* SameDirectoryAsThis)
  736.     {
  737.         FSSpec*                        NewOne;
  738.         unsigned char            Name[32] = "\pTempFile........";
  739.         int                                Scan;
  740.         unsigned long            Key;
  741.  
  742.         ERROR(-1 == ArrayFindElement(FileSpecList,SameDirectoryAsThis),PRERR(ForceAbort,
  743.             "DisposeFileSpec:  undefined file specification"));
  744.         CheckPtrExistence(SameDirectoryAsThis);
  745.         NewOne = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"SameDirectoryNewName");
  746.         if (NewOne == NIL)
  747.             {
  748.                 return NIL;
  749.             }
  750.         Key = TickCount();
  751.      TryPoint:
  752.         for (Scan = 0; Scan < 8; Scan += 1)
  753.             {
  754.                 Name[Scan + 9] = ((Key >> (Scan * 4)) & 0x0f) + 'a';
  755.             }
  756.         FSMakeFSSpec(((FSSpec*)SameDirectoryAsThis)->vRefNum,
  757.             ((FSSpec*)SameDirectoryAsThis)->parID,Name,NewOne);
  758.         LastError = FSpCreate(NewOne,'\?\?\?\?','\?\?\?\?',smSystemScript);
  759.         if (LastError == dupFNErr)
  760.             {
  761.                 Key += 1;
  762.                 goto TryPoint;
  763.             }
  764.         if (LastError != noErr)
  765.             {
  766.                 /* some other error occurred -- may be a disk full error. */
  767.                 ReleasePtr((char*)NewOne);
  768.                 NewOne = NIL;
  769.             }
  770.         if (NewOne != NIL)
  771.             {
  772.                 if (!Eep_RegisterFileSpec((FileSpec*)NewOne))
  773.                     {
  774.                         ReleasePtr((char*)NewOne);
  775.                         NewOne = NIL;
  776.                     }
  777.             }
  778.         return (FileSpec*)NewOne;
  779.     }
  780.  
  781.  
  782. /* this operation swaps the data forks for two files.  this is used for safe */
  783. /* saving (i.e. write data before clobbering so that the old file still exists */
  784. /* if the write fails).  You create a new file and write the data to it.  Then you */
  785. /* pass the location of the new file in NewFile and the location of the old */
  786. /* file in OldFile.  The routine swaps the data in the files and the last modified */
  787. /* dates.  If successful, the NewFile (temporary file) will be deleted and the */
  788. /* OldFileRef reference will be updated (it will NOT be the same) and the NewFileRef */
  789. /* will be closed. */
  790. /* NOTE:  the files should be created in the same directory. */
  791. /* this routine DOES perform operations on file descriptors. */
  792. MyBoolean                        SwapFileDataForks(FileSpec* NewAndTempFile, FileSpec* OldFile,
  793.                                             FileType* NewFileRef, FileType** OldFileRef)
  794.     {
  795.         ERROR(-1 == ArrayFindElement(FileSpecList,NewAndTempFile),PRERR(ForceAbort,
  796.             "SwapFileDataForks:  undefined file specification"));
  797.         ERROR(-1 == ArrayFindElement(FileSpecList,OldFile),PRERR(ForceAbort,
  798.             "SwapFileDataForks:  undefined file specification"));
  799.         ERROR(-1 == ArrayFindElement(FileDescriptorList,NewFileRef),PRERR(ForceAbort,
  800.             "SwapFileDataForks:  undefined file descriptor"));
  801.         ERROR(-1 == ArrayFindElement(FileDescriptorList,*OldFileRef),PRERR(ForceAbort,
  802.             "SwapFileDataForks:  undefined file descriptor"));
  803.         CheckPtrExistence(NewAndTempFile);
  804.         CheckPtrExistence(OldFile);
  805.         CheckPtrExistence(NewFileRef);
  806.         ERROR(OldFileRef == NIL,PRERR(ForceAbort,"SwapFileDataForks:  OldFileRef is NIL"));
  807.         CheckPtrExistence(*OldFileRef);
  808.         LastError = FSpExchangeFiles((FSSpec*)NewAndTempFile,(FSSpec*)OldFile);
  809.         if (LastError != noErr)
  810.             {
  811.                 return False;
  812.             }
  813.         CloseFile(*OldFileRef);
  814.         *OldFileRef = NewFileRef;
  815.         DeleteFile(NewAndTempFile);
  816.         SetTag(NewAndTempFile,"SwapFileDataForks: NewAndTempFile");
  817.         CheckPtrExistence(*OldFileRef);
  818.         return True;
  819.     }
  820.